﻿using AVCUMPlatform.BLL;
using AVCUMPlatform.BLL.Implement;
using AVCUMPlatform.BLL.Interface;
using AVCUMPlatform.CORPWXService.Interface;
using AVCUMPlatform.CORPWXService.Model;
using AVCUMPlatform.DAL;
using AVCUMPlatform.DingTalkService.Interface;
using AVCUMPlatform.DingTalkService.Model;
using AVCUMPlatform.Entities;
using AVCUMPlatform.Entities.Enum;
using AVCUMPlatform.HelperLibrary;
using AVCUMPlatform.MiniWXService;
using AVCUMPlatform.MiniWXService.Model;
using AVCUMPlatform.Model;
using AVCUMPlatform.SMSService.Interface;
using AVCUMPlatform.SMSService.Model;
using AVCUMPlatform.WXService.Interface;
using AVCUMPlatform.WXService.Model;
using Newtonsoft.Json;
using Org.BouncyCastle.Ocsp;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System.Text;

namespace AVCUMPlatform.MqConnection
{
    /// <summary>
    /// 消息处理帮助类
    /// </summary>
    public class MqConnectionHelper
    {
        private static ISystemInfoBLL _systemInfoBLL = BLLContainer.Resolve<ISystemInfoBLL>();
        #region RabbitMQ参数定义
        /// <summary>
        /// RabbitMQ工厂
        /// </summary>
        private static IConnectionFactory _connectionFactory;
        /// <summary>
        /// 配置信息
        /// </summary>
        public static List<MqConfigInfo> _mqConfig;
        /// <summary>
        /// 通道
        /// </summary>
        private static IModel channel;

        private static string _exchangeNormal = "Exchange.Normal";  //定义一个用于接收 正常 消息的交换机
        private static string _exchangeRetry = "Exchange.Retry";    //定义一个用于接收 重试 消息的交换机
        private static string _exchangeFail = "Exchange.Fail";      //定义一个用于接收 失败 消息的交换机
        private static string _queueNormal = "Queue.Noraml";        //定义一个用于接收 正常 消息的队列
        private static string _queueRetry = "Queue.Retry";          //定义一个用于接收 重试 消息的队列
        private static string _queueFail = "Queue.Fail";            //定义一个用于接收 失败 消息的队列
        /// <summary>
        /// 审批通过提醒微信模板
        /// </summary>
        public static string? bookingApprove = null;
        /// <summary>
        /// 审批驳回提醒微信模板
        /// </summary>
        public static string? bookingReject = null;
        /// <summary>
        /// 审批提醒微信模板
        /// </summary>
        public static string? auditRemind = null;
        /// <summary>
        /// 取消提醒微信模板
        /// </summary>
        public static string? bookingCancel = null;
        /// <summary>
        /// 发送给场地管理员模板
        /// </summary>
        public static string? toSiteManagerRemind = null;
        #endregion

        #region 生产者初始化连接配置
        /// <summary>
        /// 生产者初始化连接配置
        /// </summary>
        public static void FactoryConnectionInit()
        {
            _connectionFactory = new ConnectionFactory
            {
                HostName = _mqConfig.FirstOrDefault().Host,
                Port = _mqConfig.FirstOrDefault().Port,
                UserName = _mqConfig.FirstOrDefault().User,
                Password = _mqConfig.FirstOrDefault().Password,
                AutomaticRecoveryEnabled = true
            };
        }
        #endregion

        #region 生产者连接
        /// <summary>
        /// 生产者连接
        /// </summary>
        public static void SendFactoryConnection()
        {
            var connection = _connectionFactory.CreateConnection();
            channel = connection.CreateModel();

            channel.ExchangeDeclare(exchange: _exchangeNormal, type: "topic");
            channel.ExchangeDeclare(exchange: _exchangeRetry, type: "topic");
            channel.ExchangeDeclare(exchange: _exchangeFail, type: "topic");

            //定义队列参数
            var queueNormalArgs = new Dictionary<string, object>();
            {
                queueNormalArgs.Add("x-dead-letter-exchange", _exchangeFail);   //指定死信交换机，用于将 Noraml 队列中失败的消息投递给 Fail 交换机
            }
            var queueRetryArgs = new Dictionary<string, object>();
            {
                queueRetryArgs.Add("x-dead-letter-exchange", _exchangeNormal);  //指定死信交换机，用于将 Retry 队列中超时的消息投递给 Noraml 交换机
                queueRetryArgs.Add("x-message-ttl", 60000);                     //定义 queueRetry 的消息最大停留时间 (原理是：等消息超时后由 broker 自动投递给当前绑定的死信交换机)
                                                                                //定义最大停留时间为防止一些 待重新投递 的消息、没有定义重试时间而导致内存溢出
            }
            var queueFailArgs = new Dictionary<string, object>();
            {
                //暂无
            }

            //声明队列
            channel.QueueDeclare(queue: _queueNormal, durable: true, exclusive: false, autoDelete: false, arguments: queueNormalArgs);
            channel.QueueDeclare(queue: _queueRetry, durable: true, exclusive: false, autoDelete: false, arguments: queueRetryArgs);
            channel.QueueDeclare(queue: _queueFail, durable: true, exclusive: false, autoDelete: false, arguments: queueFailArgs);

            //为队列绑定交换机
            channel.QueueBind(queue: _queueNormal, exchange: _exchangeNormal, routingKey: "#");
            channel.QueueBind(queue: _queueRetry, exchange: _exchangeRetry, routingKey: "#");
            channel.QueueBind(queue: _queueFail, exchange: _exchangeFail, routingKey: "#");

            #region 创建一个普通消息消费者
            {
                var consumer = new EventingBasicConsumer(channel);

                consumer.Received += (sender, e) =>
                {
                    var _sender = (EventingBasicConsumer)sender;            //消息传送者
                    var _channel = _sender.Model;                           //消息传送通道
                    var _message = (BasicDeliverEventArgs)e;                //消息传送参数
                    var _headers = _message.BasicProperties.Headers;        //消息头
                    var _content = Encoding.UTF8.GetString(_message.Body.ToArray());  //消息内容

                    var _death = default(Dictionary<string, object>);       //死信参数

                    if (_headers != null && _headers.ContainsKey("x-death"))
                        _death = (Dictionary<string, object>)(_headers["x-death"] as List<object>)[0];

                    var msgObj = JsonConvert.DeserializeObject<MessagequeuesSend>(_content);
                    try
                    #region 消息处理
                    {
                        //消息的处理
                        var ret = MessageHandle(msgObj, out string responseMsg);
                        var status = ret ? 2 : 3;
                        if (status == 2)
                        {
                            if (!string.IsNullOrWhiteSpace(responseMsg))
                            {
                                responseMsg = responseMsg.Replace("'", "\"");
                            }
                            DapperHelper.ExecuteCommand($"update {SQLHelper.GetTableName<Messagequeues>()} set `status` = {status},`responseMsg` ='{responseMsg}' where `id` = {msgObj?.Id}");
                        }
                        if (status == 3)
                        {
                            throw new Exception("消息处理失败。");
                        }

                        _channel.BasicAck(deliveryTag: _message.DeliveryTag, multiple: false);
                    }
                    #endregion
                    catch (Exception ex)
                    #region 消息处理失败时
                    {
                        var retryCount = (long)(_death?["count"] ?? default(long)); //查询当前消息被重新投递的次数 (首次则为0)

                        //Console.WriteLine($"{DateTime.Now.ToString("HH:mm:ss.fff")}\t(1.2)处理失败：\r\n\t[deliveryTag={_message.DeliveryTag}]\r\n\t[retryCount={retryCount}]");

                        var retryCountConfig = _systemInfoBLL.GetAll().FirstOrDefault(x => x.Code == "retryCount");
                        var firstRetryIntervalTimeConfig = _systemInfoBLL.GetAll().FirstOrDefault(x => x.Code == "firstRetryIntervalTime");
                        var retryTimeGrowthConfig = _systemInfoBLL.GetAll().FirstOrDefault(x => x.Code == "retryTimeGrowth");
                        if (retryCount >= Convert.ToInt32(retryCountConfig.Value))
                        #region 投递第{retryCountConfig}次还没消费成功时，就转发给 exchangeFail 交换机
                        {
                            //消息拒绝（投递给死信交换机，也就是上边定义的 ("x-dead-letter-exchange", _exchangeFail)）
                            _channel.BasicNack(deliveryTag: _message.DeliveryTag, multiple: false, requeue: false);
                        }
                        #endregion
                        else
                        #region 否则转发给 exchangeRetry 交换机
                        {
                            Log.Write($"\t处理失败重发：\r\n\t[msgId={msgObj?.Id}]\r\n\t[retryCount={retryCount + 1}]");
                            var interval = ((int)Math.Pow(Convert.ToInt32(retryTimeGrowthConfig.Value), retryCount)) * Convert.ToInt32(firstRetryIntervalTimeConfig.Value); //定义下一次投递的间隔时间 (单位：秒)
                            //定义下一次投递的间隔时间 (单位：毫秒)
                            _message.BasicProperties.Expiration = (interval * 1000).ToString();                                                                               //如：首次重试间隔10秒、第二次间隔20秒、第三次间隔30秒

                            //将消息投递给 _exchangeRetry (会自动增加 death 次数)
                            _channel.BasicPublish(exchange: _exchangeRetry, routingKey: _message.RoutingKey, basicProperties: _message.BasicProperties, body: _message.Body);

                            //消息确认 (销毁当前消息)
                            _channel.BasicAck(deliveryTag: _message.DeliveryTag, multiple: false);
                        }
                        #endregion
                    }
                    #endregion
                };
                channel.BasicConsume(queue: _queueNormal, autoAck: false, consumer: consumer);
            }
            #endregion

            #region 创建一个失败消息消费者
            {
                var consumer = new EventingBasicConsumer(channel);

                consumer.Received += (sender, e) =>
                {
                    var _message = (BasicDeliverEventArgs)e;                //消息传送参数
                    var _content = Encoding.UTF8.GetString(_message.Body.ToArray());  //消息内容
                };

                channel.BasicConsume(queue: _queueFail, autoAck: true, consumer: consumer);
            }
            #endregion
        }
        #endregion

        #region 消息发布
        /// <summary>
        /// 消息发布
        /// </summary>
        /// <param name="message">消息</param>
        /// <param name="routingKey"></param>
        public static void PublishExchange(string message, string routingKey)
        {
            var msgContent = $"消息内容_{DateTime.Now.ToString("HH:mm:ss.fff")}_{message}";
            byte[] body = Encoding.UTF8.GetBytes(message);
            var props = channel.CreateBasicProperties();
            channel.BasicPublish(_exchangeNormal, routingKey, props, body);
            Console.WriteLine($"{DateTime.Now.ToString("HH:mm:ss.fff")}\t发送成功：{msgContent}");
        }
        #endregion

        #region 消息处理
        /// <summary>
        /// 消息处理
        /// </summary>
        /// <param name="msgObj"></param>
        /// <param name="responseMsg"></param>
        /// <returns></returns>
        public static bool MessageHandle(MessagequeuesSend msgObj, out string responseMsg)
        {
            responseMsg = "";
            try
            {
                if (msgObj.SendType <= 0 || string.IsNullOrWhiteSpace(msgObj.Content) || msgObj.Source <= 0)
                {
                    throw new Exception("发送方式/消息内容/来源参数无效");
                }

                if (msgObj.SendType == (int)ClientTypeEnum.WX)
                {
                    #region 微信
                    IWXPlatformApiHelper? instance = null;
                    try
                    {
                        instance = ApiHelperFactory.GetWXInstance(msgObj.Source);
                        if (instance == null)
                        {
                            throw new Exception("微信配置信息不存在");
                        }
                        if (msgObj.Msgtype == "WX_Lib_PublishMenu")
                        {
                            var ret = instance.PublishMenu(msgObj.Content);
                            if (ret == null)
                            {
                                throw new Exception("发送失败");
                            }
                            responseMsg = JsonConvert.SerializeObject(ret);
                            if (ret.errcode == 0)
                            {
                                return true;
                            }
                            else
                            {
                                throw new Exception(ret.errmsg);
                            }
                        }
                        else
                        {
                            var content = JsonConvert.DeserializeObject<WXTemplateMsgRM>(msgObj.Content);
                            if (content == null)
                            {
                                throw new Exception("消息内容为空");
                            }

                            var ret = instance.SendTemplateMsg(content);
                            if (ret == null)
                            {
                                throw new Exception("发送失败");
                            }

                            responseMsg = JsonConvert.SerializeObject(ret);
                            if (ret.msgid != null)
                            {
                                return true;
                            }
                            else
                            {
                                throw new Exception(ret.errmsg);
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        Log.WriteException(ex);
                        var exmsg = ex.Message;
                        if (!string.IsNullOrWhiteSpace(exmsg))
                        {
                            exmsg = exmsg.Replace("'", "\"");
                        }
                        DapperHelper.ExecuteCommand($"update {SQLHelper.GetTableName<Messagequeues>()} set `status` = 3,`responseMsg` ='{exmsg}' where `id` = {msgObj.Id}");
                    } 
                    #endregion
                }
                else if (msgObj.SendType == (int)ClientTypeEnum.DT)
                {
                    #region 钉钉
                    IDingPlatformApiHelper? instance = null;
                    try
                    {
                        instance = ApiHelperFactory.GetDingInstance(msgObj.Source);
                        if (instance == null)
                        {
                            throw new Exception("钉钉配置信息不存在");
                        }
                        DingTalkSendMsg? ret = null;
                        if (msgObj.Msgtype == "DT_SendMsg_Supervision" || msgObj.Msgtype == "DT_SendMsgByPhone")
                        {
                            var sendJson = JsonConvert.DeserializeObject<DingTalkSendText>(msgObj.Content);
                            if (sendJson == null)
                            {
                                throw new Exception("消息内容为空");
                            }
                            ret = instance.DingSendPersonalRemindMsg(sendJson.userPhones, sendJson.userIds, sendJson.content);
                            if (ret == null)
                            {
                                throw new Exception("发送失败");
                            }
                        }
                        else if (msgObj.Msgtype == "DT_SendMsg_Robot")
                        {
                            var sendJson = JsonConvert.DeserializeObject<Robot>(msgObj.Content);
                            if (sendJson == null)
                            {
                                throw new Exception("消息内容为空");
                            }
                            ret = instance.SendRobotMsg(sendJson);
                            if (ret == null)
                            {
                                throw new Exception("发送失败");
                            }
                        }
                        else
                        {
                            var sendJson = JsonConvert.DeserializeObject<DingTalkAsyncSend>(msgObj.Content);
                            if (sendJson == null)
                            {
                                throw new Exception("消息内容为空");
                            }

                            ret = instance.SendTemplateMsg(sendJson);
                            if (ret == null)
                            {
                                throw new Exception("发送失败");
                            }
                        }

                        responseMsg = JsonConvert.SerializeObject(ret);
                        if (ret.errcode == 0)
                        {
                            return true;
                        }
                        else
                        {
                            throw new Exception(ret.errmsg);
                        }
                    }
                    catch (Exception ex)
                    {
                        Log.WriteException(ex);
                        var exmsg = ex.Message;
                        if (!string.IsNullOrWhiteSpace(exmsg))
                        {
                            exmsg = exmsg.Replace("'", "\"");
                        }
                        DapperHelper.ExecuteCommand($"update {SQLHelper.GetTableName<Messagequeues>()} set `status` = 3,`responseMsg` ='{exmsg}' where `id` = {msgObj.Id}");
                    } 
                    #endregion
                }
                else if (msgObj.SendType == (int)ClientTypeEnum.CORPWX)
                {
                    #region 企业微信
                    ICorpWXPlatformApiHelper? instance = null;
                    try
                    {
                        instance = ApiHelperFactory.GetCorpWXInstance(msgObj.Source);
                        if (instance == null)
                        {
                            throw new Exception("企业微信配置信息不存在");
                        }
                        if (msgObj.Msgtype == "CORPWX_Lib_PublishMenu")
                        {
                            var ret = instance.PublishMenu(msgObj.Content);
                            if (ret == null)
                            {
                                throw new Exception("发送失败");
                            }
                            responseMsg = JsonConvert.SerializeObject(ret);
                            if (ret.errcode == 0)
                            {
                                return true;
                            }
                            else
                            {
                                throw new Exception(ret.errmsg);
                            }
                        }
                        else if (msgObj.Msgtype == "CORPWX_SendMsgByPhone")
                        {
                            var sendJson = JsonConvert.DeserializeObject<CorpWXSendText>(msgObj.Content);
                            if (sendJson == null)
                            {
                                throw new Exception("消息内容为空");
                            }
                            var rets = instance.SendNormalMsgByPhones(sendJson.userPhones, sendJson.content);
                            if (rets == null)
                            {
                                throw new Exception("发送失败");
                            }
                            responseMsg = JsonConvert.SerializeObject(rets);
                            if (rets.msgid != null)
                            {
                                return true;
                            }
                            else
                            {
                                throw new Exception(rets.errmsg);
                            }
                        }
                        else
                        {
                            var content = JsonConvert.DeserializeObject<CorpWXTemplateMsgRM>(msgObj.Content);
                            if (content == null)
                            {
                                throw new Exception("消息内容为空");
                            }

                            var ret = instance.SendTemplateMsg(content);
                            if (ret == null)
                            {
                                throw new Exception("发送失败");
                            }

                            responseMsg = JsonConvert.SerializeObject(ret);
                            if (ret.msgid != null)
                            {
                                return true;
                            }
                            else
                            {
                                throw new Exception(ret.errmsg);
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        Log.WriteException(ex);
                        var exmsg = ex.Message;
                        if (!string.IsNullOrWhiteSpace(exmsg))
                        {
                            exmsg = exmsg.Replace("'", "\"");
                        }
                        DapperHelper.ExecuteCommand($"update {SQLHelper.GetTableName<Messagequeues>()} set `status` = 3,`responseMsg` ='{exmsg}' where `id` = {msgObj.Id}");
                    } 
                    #endregion
                }
                else if (msgObj.SendType == (int)ClientTypeEnum.MINIWX)
                {
                    #region 微信小程序
                    IMiniWXPlatformApiHelper? instance = null;
                    try
                    {
                        instance = ApiHelperFactory.GetMiniWXInstance(msgObj.Source);
                        if (instance == null)
                        {
                            throw new Exception("微信小程序配置信息不存在");
                        }
                        var content = JsonConvert.DeserializeObject<MiniWXTemplateMsgRM>(msgObj.Content);
                        if (content == null)
                        {
                            throw new Exception("消息内容为空");
                        }

                        var ret = instance.SendTemplateMsg(content);
                        if (ret == null)
                        {
                            throw new Exception("发送失败");
                        }

                        responseMsg = JsonConvert.SerializeObject(ret);
                        if (ret.msgid != null)
                        {
                            return true;
                        }
                        else
                        {
                            throw new Exception(ret.errmsg);
                        }
                    }
                    catch (Exception ex)
                    {
                        Log.WriteException(ex);
                        var exmsg = ex.Message;
                        if (!string.IsNullOrWhiteSpace(exmsg))
                        {
                            exmsg = exmsg.Replace("'", "\"");
                        }
                        DapperHelper.ExecuteCommand($"update {SQLHelper.GetTableName<Messagequeues>()} set `status` = 3,`responseMsg` ='{exmsg}' where `id` = {msgObj.Id}");
                    }
                    #endregion
                }
                else if (msgObj.SendType == (int)ClientTypeEnum.SMS)
                {
                    #region 短信
                    ISMSPlatformApiHelper? instance = null;
                    try
                    {
                        instance = ApiHelperFactory.GetSMSInstance(msgObj.Source);
                        if (instance == null)
                        {
                            throw new Exception("短信配置信息不存在");
                        }
                        SMSRes? ret = null;
                        if (msgObj.Msgtype == "SMS_SendMsg")
                        {
                            var sendJson = JsonConvert.DeserializeObject<SMSSendContent>(msgObj.Content);
                            if (sendJson == null)
                            {
                                throw new Exception("消息内容为空");
                            }
                            ret = instance.SendTemplateMsg(sendJson);
                            if (ret == null)
                            {
                                throw new Exception("发送失败");
                            }
                        }

                        responseMsg = JsonConvert.SerializeObject(ret);
                        if (ret != null && ret.code == 1)
                        {
                            return true;
                        }
                        else
                        {
                            throw new Exception("发送失败");
                        }
                    }
                    catch (Exception ex)
                    {
                        Log.WriteException(ex);
                        var exmsg = ex.Message;
                        if (!string.IsNullOrWhiteSpace(exmsg))
                        {
                            exmsg = exmsg.Replace("'", "\"");
                        }
                        DapperHelper.ExecuteCommand($"update {SQLHelper.GetTableName<Messagequeues>()} set `status` = 3,`responseMsg` ='{exmsg}' where `id` = {msgObj.Id}");
                    }
                    #endregion
                }
                return false;
            }
            catch (Exception ex)
            {
                Log.WriteException(ex);
                var exmsg = ex.Message;
                if (!string.IsNullOrWhiteSpace(exmsg))
                {
                    exmsg = exmsg.Replace("'", "\"");
                }
                DapperHelper.ExecuteCommand($"update {SQLHelper.GetTableName<Messagequeues>()} set `status` = 3,`responseMsg` ='{exmsg}' where `id` = {msgObj.Id}");
                throw;
            }
        }
        #endregion
    }
}
